/*
This file is part of BGSLibrary.

BGSLibrary is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

BGSLibrary is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

/*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)'
static const int s_nSamplesInitPatternWidth = 3;
static const int s_nSamplesInitPatternHeight = 3;
static const int s_nSamplesInitPatternTot = 256;
static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
    {19,    32,    19,},
    {32,    52,    32,},
    {19,    32,    19,},
};*/

// gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)'
static const int s_nSamplesInitPatternWidth = 7;
static const int s_nSamplesInitPatternHeight = 7;
static const int s_nSamplesInitPatternTot = 512;
static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = {
  {2,     4,     6,     7,     6,     4,     2,},
  {4,     8,    12,    14,    12,     8,     4,},
  {6,    12,    21,    25,    21,    12,     6,},
  {7,    14,    25,    28,    25,    14,     7,},
  {6,    12,    21,    25,    21,    12,     6,},
  {4,     8,    12,    14,    12,     8,     4,},
  {2,     4,     6,     7,     6,     4,     2,},
};

//! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
  int r = 1+rand()%s_nSamplesInitPatternTot;
  for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) {
    for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) {
      r -= s_anSamplesInitPattern[y_sample][x_sample];
      if(r<=0)
        goto stop;
    }
  }
stop:
  x_sample += x_orig-s_nSamplesInitPatternWidth/2;
  y_sample += y_orig-s_nSamplesInitPatternHeight/2;
  if(x_sample<border)
    x_sample = border;
  else if(x_sample>=imgsize.width-border)
    x_sample = imgsize.width-border-1;
  if(y_sample<border)
    y_sample = border;
  else if(y_sample>=imgsize.height-border)
    y_sample = imgsize.height-border-1;
}

// simple 8-connected (3x3) neighbors pattern
static const int s_anNeighborPatternSize_3x3 = 8;
static const int s_anNeighborPattern_3x3[8][2] = {
  {-1, 1},  { 0, 1},  { 1, 1},
  {-1, 0},            { 1, 0},
  {-1,-1},  { 0,-1},  { 1,-1},
};

//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
  int r = rand()%s_anNeighborPatternSize_3x3;
  x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0];
  y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1];
  if(x_neighbor<border)
    x_neighbor = border;
  else if(x_neighbor>=imgsize.width-border)
    x_neighbor = imgsize.width-border-1;
  if(y_neighbor<border)
    y_neighbor = border;
  else if(y_neighbor>=imgsize.height-border)
    y_neighbor = imgsize.height-border-1;
}

// 5x5 neighbors pattern
static const int s_anNeighborPatternSize_5x5 = 24;
static const int s_anNeighborPattern_5x5[24][2] = {
  {-2, 2},  {-1, 2},  { 0, 2},  { 1, 2},  { 2, 2},
  {-2, 1},  {-1, 1},  { 0, 1},  { 1, 1},  { 2, 1},
  {-2, 0},  {-1, 0},            { 1, 0},  { 2, 0},
  {-2,-1},  {-1,-1},  { 0,-1},  { 1,-1},  { 2,-1},
  {-2,-2},  {-1,-2},  { 0,-2},  { 1,-2},  { 2,-2},
};

//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check.
static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) {
  int r = rand()%s_anNeighborPatternSize_5x5;
  x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0];
  y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1];
  if(x_neighbor<border)
    x_neighbor = border;
  else if(x_neighbor>=imgsize.width-border)
    x_neighbor = imgsize.width-border-1;
  if(y_neighbor<border)
    y_neighbor = border;
  else if(y_neighbor>=imgsize.height-border)
    y_neighbor = imgsize.height-border-1;
}
